/*
 * @Descripttion: 基于八叉树的碰撞检测控制器，v0.2
 * @version:
 * @Author: 刘译蓬
 * @Date: 2022-07-12 13:38:28
 * @LastEditors: 刘译蓬
 * @LastEditTime: 2022-07-12 16:12:55
 */
import { Vector3 } from 'three'
import { Octree } from 'three/addons/math/Octree.js'
import { Capsule } from 'three/addons/math/Capsule.js'

class CollisionController {
	// private camera, // 相机
	// private collisionGroup:Object3D// 需要计算碰撞检测的组
	// private canvas:HTMLCanvasElement
	// private worldOctree:Octree// 环境八叉树
	// private playerCollider!: Capsule // 玩家碰撞体积
	// private playerDirection:Vector3// 玩家方向

	/**
	 * @Descripttion:
	 * @Author: 刘译蓬
	 * @msg:
	 * @param {PerspectiveCamera} 相机
	 * @param {HTMLCanvasElement} 画布
	 * @param {iCapsule} 碰撞体积
	 * @param {Object3D} 需要检测碰撞的组
	 * @param {Vector3} 位置
	 * @return {*}
	 */
	constructor({ camera, canvas, capsuleParam, collisionGroup, position, speedDelta }) {
		this.worldOctree = new Octree()
		this.playerCollider = new Capsule(capsuleParam.start, capsuleParam.end, capsuleParam.radius)
		if (position) this.playerCollider.translate(position)
		this.playerDirection = new Vector3()
		this.camera = camera
		this.camera.rotation.order = 'YXZ' // 相机旋转方式需要调整一下
		this.collisionGroup = collisionGroup
		this.canvas = canvas || document
		this.eventStates = {
			// 事件状态
			KeyW: false,
			KeyA: false,
			KeyS: false,
			KeyD: false,
			Space: false,
			mouseDown: false
		}
		this.speedDelta = speedDelta || 0.3
		this.initWorld() // 初始化碰撞检测
		this.initEventListener() // 初始化事件侦听
	}

	/**
	 * @Descripttion: 初始化碰撞
	 * @Author: 刘译蓬
	 * @msg:
	 * @return {*}
	 */
	initWorld() {
		this.worldOctree.fromGraphNode(this.collisionGroup)
	}

	/**
	 * @Descripttion: 初始化按键侦听
	 * @Author: 刘译蓬
	 * @msg:
	 * @return {*}
	 */
	initEventListener() {
		// 键盘按下
		document.addEventListener('keydown', (event) => {
			switch (event.code) {
				case 'KeyW':
					this.eventStates[event.code] = true
					break
				case 'KeyA':
					this.eventStates[event.code] = true
					break
				case 'KeyS':
					this.eventStates[event.code] = true
					break
				case 'KeyD':
					this.eventStates[event.code] = true
					break
				case 'Space':
					this.eventStates[event.code] = true
					break
				default:
					break
			}
		})
		// 键盘抬起
		document.addEventListener('keyup', (event) => {
			switch (event.code) {
				case 'KeyW':
					this.eventStates[event.code] = false
					break
				case 'KeyA':
					this.eventStates[event.code] = false
					break
				case 'KeyS':
					this.eventStates[event.code] = false
					break
				case 'KeyD':
					this.eventStates[event.code] = false
					break
				case 'Space':
					this.eventStates[event.code] = false
					break
				default:
					break
			}
		})
		// 鼠标按下
		this.canvas.addEventListener('mousedown', () => {
			this.eventStates.mouseDown = true
		})
		// 鼠标抬起
		this.canvas.addEventListener('mouseup', () => {
			this.eventStates.mouseDown = false
		})
		// 鼠标移动
		this.canvas.addEventListener('mousemove', (event) => {
			if (this.eventStates.mouseDown) {
				this.camera.rotation.y -= event.movementX / 500
				this.camera.rotation.x -= event.movementY / 500
			}
		})
	}

	/**
	 * @Descripttion: 更新玩家
	 * @Author: 刘译蓬
	 * @msg:
	 * @return {*}
	 */
	updatePlayer() {
		// 判断是否碰撞
		const result = this.worldOctree.capsuleIntersect(this.playerCollider)
		// 碰撞了恢复到未碰撞位置
		if (result) {
			requestAnimationFrame(() => {
				this.playerCollider.translate(result.normal.multiplyScalar(-result.depth))
			})
		}
		this.camera.position.copy(this.playerCollider.end)
	}

	/**
	 * @Descripttion: 获得前后方向
	 * @Author: 刘译蓬s
	 * @msg:
	 * @return {*}
	 */
	getForwardVector() {
		this.camera.getWorldDirection(this.playerDirection)
		this.playerDirection.y = 0
		this.playerDirection.normalize()
		return this.playerDirection
	}

	/**
	 * @Descripttion: 获得左右方向
	 * @Author: 刘译蓬
	 * @msg:
	 * @return {*}
	 */
	getSideVector() {
		this.camera.getWorldDirection(this.playerDirection)
		this.playerDirection.y = 0
		this.playerDirection.normalize()
		this.playerDirection.cross(this.camera.up)
		return this.playerDirection
	}

	/**
	 * @Descripttion: 控制器
	 * @Author: 刘译蓬
	 * @return {*}
	 */
	controls() {
		if (this.eventStates.KeyW) {
			// 玩家碰撞体积 移动
			this.playerCollider.translate(this.getForwardVector().multiplyScalar(this.speedDelta))
		}
		if (this.eventStates.KeyS) {
			this.playerCollider.translate(this.getForwardVector().multiplyScalar(-this.speedDelta))
		}
		if (this.eventStates.KeyA) {
			this.playerCollider.translate(this.getSideVector().multiplyScalar(-this.speedDelta))
		}
		if (this.eventStates.KeyD) {
			this.playerCollider.translate(this.getSideVector().multiplyScalar(this.speedDelta))
		}
	}

	/**
	 * @Descripttion: 更新控制器
	 * @Author: 刘译蓬
	 * @msg:
	 * @return {*}
	 */
	update() {
		this.controls()
		this.updatePlayer()
	}
}
export { CollisionController }
